//
//  UserDataViewModel.swift
//  IdleFish
//
//  Created by Ben on 2021/12/21.
//

import SwiftUI
import Combine
import Alamofire

@MainActor
class UserDataViewModel: ObservableObject, BenHUDAble {
    
    
    @Published var initVM: InitViewModel?
    @Published var handleUrl: String?
    
    @Published var permanentAddrSaveBtnIsEnabled: Bool = false
    @Published var provinceList: [ProvinceModel] = []
    @Published var selectedProvince: ProvinceModel?
    @Published var cityList: [CityModel] = []
    @Published var selectedCity: CityModel?
    
    private var isSelectedProvincePublisher: AnyPublisher<Bool, Never> {
        $selectedProvince
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .removeDuplicates()
            .map { $0 != nil }
            .eraseToAnyPublisher()
    }
    private var isSelectedCityPublisher: AnyPublisher<Bool, Never> {
        $selectedCity
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .removeDuplicates()
            .map { $0 != nil }
            .eraseToAnyPublisher()
    }
    
    private var permanentAddrSaveBtnIsEnabledValidPublisher: AnyPublisher<Bool, Never> {
        Publishers.CombineLatest(isSelectedProvincePublisher, isSelectedCityPublisher)
            .debounce(for: 0.2, scheduler: RunLoop.main)
            .map { $0 == true && $1 == true }
            .eraseToAnyPublisher()
    }
    
    @Published var showPermanentAddr: Bool = false
    @Published var selectedPermanentAddr: String = ""
    
    @Published var showPositionPicker: Bool = false
    @Published var selectedPosition: String = ""
    
    @Published var showIndustryPicker: Bool = false
    @Published var selectedIndustry: String = ""
    
    @Published var showBrithdayPicker: Bool = false
    @Published var selectedBrithdayDate: Date = Date()
    
    // 控制性别选择器的显示和隐藏
    @Published var showGenderPicker: Bool = false
    @Published var selectedGender: UserGender = .unknow
    
    // 选择完成将要上传的图片
    @Published var selectedHandleImage: UIImage?
    @Published var uploadedHandle: String?
    
    // 控制选择图片上传alert的显示
    @Published var showSelectImageType: Bool = false
    // 控制图片选择器的显示和隐藏
    @Published var showImagePicker: Bool = false
    // 控制是从相册选择图片还是从相机获取图片
    @Published var photoSource: UIImagePickerController.SourceType = .photoLibrary
    
    // 控制修改昵称页面的push和pop
    @Published var pushSetNickNameView: Bool = false
    
    // 用户昵称
    @Published var nickName: String = ""
    // 更新用户昵称是否可用
    @Published var updateNickNameIsEnabled: Bool = true

    private var cancellable: Set<AnyCancellable> = []

    
    // 当selectedHandleImage值改变之后，需要触发上传图片的方法
    private func uploadImage(image: UIImage) async throws -> String? {
        
        do {
            
            let result = try await NetworkTool.uploadImageToSMMS(image: image)
            
            return result.data?.url
        } catch {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
            
            return nil
        }
    }
    
    
    /// 更新用户头像
    /// - Parameters:
    ///   - user_id: 用户id
    ///   - avatar: 上传到图床的头像地址
    /// - Returns: 返回bool，true表示成功，false表示失败
    private func updateUserAvatar(user_id: Int, avatar: String) async throws -> Bool {
        
        self.wait(message: "修改头像", gifImageName: "hud_wait.gif")
        do {
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: user_id, value: avatar, user_data_action: UserDataAction.handle.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                return true
            }
            self.show(message: "更新失败")
            return false
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                default:
                    self.show(message: "更新失败")
                }
            }
            
            return false
        }
    }
    
    
    /// 更新用户头像的外部调用方法
    /// - Parameters:
    ///   - user_id: 用户id
    ///   - handleImage: 要更新的头像名称
    func updateUserHandle(user_id: Int, handleImage: UIImage) async {
        
        self.wait(message: "正在更新头像", gifImageName: "hud_wait.gif")
        do {
            
            guard let handleUrl = try await self.uploadImage(image: handleImage) else {
                
                self.show(message: "图片上传失败")
                return
            }
            
            Dlog(handleUrl)
            let result = try await self.updateUserAvatar(user_id: 3, avatar: handleUrl)
            
            if result {
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                self.uploadedHandle = handleUrl
                self.initVM?.initModel?.user_info?.avatar = handleUrl
            } else {
                self.show(message: "更新失败")
            }

        } catch {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    
    func updateUserNickName(user_id: Int, nick_name: String) async -> Bool {
        
        
        do {
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: user_id, value: nick_name, user_data_action: UserDataAction.nickName.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                return true
            }
            
            return false
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
            
            return false
        }
    }
    
    func updateUserGender() async {
        
        self.wait(message: "正在更新性别", gifImageName: "hud_wait.gif")

        do {
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: initVM?.userInfo?.id ?? 0, value: String(selectedGender.rawValue ?? 0), user_data_action: UserDataAction.gender.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                // 为initModel中的user_info更新性别信息
                self.initVM?.initModel?.user_info?.gender = selectedGender.rawValue
                withAnimation {
                    // 关闭性别选择器
                    self.showGenderPicker.toggle()
                }
                return
            }
            
            self.show(message: "更新失败", systemImageName: "xmark.seal.fill")
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    func updateUserBirthday() async {
        
        self.wait(message: "正在更新生日", gifImageName: "hud_wait.gif")

        do {
            let brithdayValue = String(Int(selectedBrithdayDate.timeIntervalSince1970  * 1000))
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: initVM?.userInfo?.id ?? 0, value: brithdayValue, user_data_action: UserDataAction.birthday.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                // 为initModel中的user_info更新性别信息
                self.initVM?.initModel?.user_info?.birthday = brithdayValue
                withAnimation {
                    // 关闭生日日期选择器
                    self.showBrithdayPicker.toggle()
                }
                return
            }
            
            self.show(message: "更新失败", systemImageName: "xmark.seal.fill")
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    func updateIndustry() async {
        
        self.wait(message: "正在更新行业", gifImageName: "hud_wait.gif")

        do {
            
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: initVM?.userInfo?.id ?? 0, value: selectedIndustry, user_data_action: UserDataAction.industry.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                // 为initModel中的user_info更新性别信息
                self.initVM?.initModel?.user_info?.industry = selectedIndustry
                withAnimation {
                    // 关闭生日日期选择器
                    self.showIndustryPicker.toggle()
                }
                return
            }
            
            self.show(message: "更新失败", systemImageName: "xmark.seal.fill")
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    func updatePosition() async {
        
        self.wait(message: "正在更新职位", gifImageName: "hud_wait.gif")

        do {
            
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: initVM?.userInfo?.id ?? 0, value: selectedPosition, user_data_action: UserDataAction.position.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                // 为initModel中的user_info更新性别信息
                self.initVM?.initModel?.user_info?.position = selectedPosition
                withAnimation {
                    // 关闭生日日期选择器
                    self.showPositionPicker.toggle()
                }
                return
            }
            
            self.show(message: "更新失败", systemImageName: "xmark.seal.fill")
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    func loadCity() async {
        guard let cityJsonFilePath = Bundle.main.path(forResource: "city.json", ofType: nil) else {
            return
        }
        let cityJsonFileUrl = URL(fileURLWithPath: cityJsonFilePath)
        guard let cityData = try? Data(contentsOf: cityJsonFileUrl) else {
            return
        }
        guard let cityJson = try? JSONSerialization.jsonObject(with: cityData, options: .mutableLeaves) as? [String: AnyObject] else {
            return
        }
        var provinceList: [ProvinceModel] = []
        cityJson.forEach { cityDict in
            let provinceId = cityDict.key
            let provinceListDict = cityDict.value as? [[String: AnyObject]]
            let provinceName = provinceListDict?.first?["province"] as? String
            
            let provinceModel = ProvinceModel()
            provinceModel.id = provinceId
            provinceModel.name = provinceName
            
            provinceList.append(provinceModel)
            
            provinceListDict?.forEach({ cityDict in
                
                let cityId = cityDict["id"] as? String
                let cityName = cityDict["name"] as? String
                
                let cityModel = CityModel()
                cityModel.id = cityId
                cityModel.name = cityName
                
                provinceModel.city_list.append(cityModel)
            })
        }
        
        provinceList.forEach { provinceModel in
            provinceModel.city_list.sort { Int($0.id ?? "0")! < Int($1.id ?? "0")! }
        }
        
        provinceList.sort { Int($0.id ?? "0")! < Int($1.id ?? "0")! }
        
        self.provinceList = provinceList
    }
    
    func updatePermanentAddr() async {
        
        self.wait(message: "正在更新常住地", gifImageName: "hud_wait.gif")

        do {
            let permanentAddr = "\(selectedProvince?.name ?? "") \(selectedCity?.name ?? "")"
            let result = try await NetworkTool.awaitRequest(request: API.update_user_value(user_id: initVM?.userInfo?.id ?? 0, value: permanentAddr, user_data_action: UserDataAction.address.rawValue), responseType: NetworkNilModel.self)
            
            if result.code == 1 {
                
                self.show(message: "更新成功", systemImageName: "checkmark.seal")
                // 为initModel中的user_info更新性别信息
                self.initVM?.initModel?.user_info?.address = permanentAddr
                withAnimation {
                    // 关闭生日日期选择器
                    self.showPermanentAddr.toggle()
                }
                return
            }
            
            self.show(message: "更新失败", systemImageName: "xmark.seal.fill")
            
        } catch  {
            
            if let e = error as? APIError {
                switch e {
                case .custom(let msg):
                    self.show(message: msg, systemImageName: "xmark.seal.fill")
                }
            }
        }
    }
    
    
    init() {
        $selectedHandleImage
            .dropFirst()
            .removeDuplicates()
            .debounce(for: 0.25, scheduler: RunLoop.main)
            .sink { _image in
                Task {
                    await self.updateUserHandle(user_id: self.initVM?.userInfo?.id ?? 0, handleImage: _image!)
                }
            }
            .store(in: &cancellable)
        
        $selectedIndustry
            .dropFirst()
            .removeDuplicates()
            .debounce(for: 0.25, scheduler: RunLoop.main)
            .sink { _selectedIndustry in
                Task {
                    await self.updateIndustry()
                }
            }
            .store(in: &cancellable)
        
        $selectedPosition
            .dropFirst()
            .removeDuplicates()
            .debounce(for: 0.25, scheduler: RunLoop.main)
            .sink { _selectedIndustry in
                Task {
                    await self.updatePosition()
                }
            }
            .store(in: &cancellable)
        
        $selectedProvince
            .dropFirst()
            .removeDuplicates()
            .sink { _selectedProvince in
                self.cityList = _selectedProvince?.city_list ?? []
            }
            .store(in: &cancellable)
        
        permanentAddrSaveBtnIsEnabledValidPublisher
            .sink { isEnabled in
                self.permanentAddrSaveBtnIsEnabled = isEnabled
            }
            .store(in: &cancellable)
    }
    
    
}
